
package ch.hearc.securiteSysteme.serie2.ex2ChallengeResponse.server;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 
 * @author Raphaël Capocasale
 *
 */
public class SocketServer implements Server_I
	{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 493747417062983371L;
	/*------------------------------------------------------------------*\
	|*							Attributs Private						*|
	\*------------------------------------------------------------------*/
	//tools
	private ServerSocket m_serverSocket;
	private Socket m_socket;
	private ObjectOutputStream m_outObject;
	private ObjectInputStream m_inObject;
	private OnMessageListener_I m_onMessageListener;
	private Reception m_reception;
	private Thread m_threadReception;
	private boolean m_isReceptionCreated;
	private boolean m_isServerListening;
	private boolean m_isServerStarted;
	private int m_serverPort;
	
	/*------------------------------*\
	|*			  Static			*|
	\*------------------------------*/
	static public final int DEFAULT_PORT = 40000;
	
	/*------------------------------------------------------------------*\
	|*							Constructeurs							*|
	\*------------------------------------------------------------------*/
	public SocketServer()
		{
		m_socket = null;
		m_inObject = null;
		m_reception = null;
		m_isReceptionCreated = false;
		m_isServerListening = false;
		m_isServerStarted = false;
		m_serverPort = SocketServer.DEFAULT_PORT;
		}
	
	/*------------------------------------------------------------------*\
	|*							Methodes Public							*|
	\*------------------------------------------------------------------*/
	public void setPort(int port)
		{
		m_serverPort = port;
		}
	
	public void send(final Object obj)
		{
		try
			{
			Thread.sleep(75);
			}
		catch (InterruptedException e)
			{
			e.printStackTrace();
			}
		try
			{
			if (m_outObject != null)
				{
				m_outObject.writeObject(obj);
				m_outObject.flush();
				}
			else
				{
				throw new IOException();
				}
			}
		catch (IOException e)
			{
			m_onMessageListener.onClientDisconnected(SocketServer.this, obj);
			}
		}
	
	public void start() throws IOException
		{
		if (!m_isServerStarted)
			{
			m_isServerStarted = true;
			m_serverSocket = new ServerSocket(m_serverPort);
			
			m_onMessageListener.onNotification("The server listens port " + m_serverSocket.getLocalPort() + " on address " + InetAddress.getLocalHost());
			
			new Thread(new Runnable()
				{
					
					public void run()
						{
						m_isServerListening = true;
						
						while(m_isServerListening)
							{
							try
								{
								m_socket = m_serverSocket.accept();
								m_inObject = new ObjectInputStream(m_socket.getInputStream());
								m_outObject = new ObjectOutputStream(m_socket.getOutputStream());
								new Thread(new Runnable()
									{
										
										public void run()
											{
											m_onMessageListener.onClientConnected(SocketServer.this);
											}
									}).start();
								
								if (!m_isReceptionCreated)
									{
									m_reception = new Reception();
									m_reception.setInObject(m_inObject);
									m_reception.setOnMessageListener(new OnMessageListener_I()
										{
											
											public void onMessageReceived(Object obj)
												{
												m_onMessageListener.onMessageReceived(obj);
												}
											
											public void onNotification(String notification)
												{
												m_onMessageListener.onNotification(notification);
												}
											
											public void onClientConnected(Server_I server)
												{
												//rien                                												
												}
											
											public void onClientDisconnected(Server_I server, Object obj)
												{
												//rien                                                                                              
												}
											
										});
									
									m_threadReception = new Thread(m_reception);
									m_threadReception.start();
									
									m_isReceptionCreated = true;
									}
								else
									{
									m_reception.setInObject(m_inObject);
									}
								}
							catch (Exception e)
								{
								//rien
								}
							}
						}
					
				}).start();
			
			}
		else
			{
			m_onMessageListener.onNotification("The server is already created !");
			}
		}
	
	public void setOnMessageListener(OnMessageListener_I listener)
		{
		m_onMessageListener = listener;
		}
	
	/**
	 * <pre>
	 * Cette méthode termine la tache asynchrone de réception de message
	 * et ferme les flux utilisés pour l'envoi et la réception de données.
	 * Les sockets sont également fermés.
	 * </pre>
	 * @throws IOException 
	 */
	public void stop() throws IOException
		{
		m_isServerListening = false;
		
		if (m_reception != null)
			{
			m_reception.cancel();
			
			if (m_threadReception.isAlive())
				{
				m_threadReception.interrupt();
				}
			}
		
		if (m_inObject != null)
			{
			m_inObject.close();
			}
		if (m_outObject != null)
			{
			m_outObject.close();
			}
		if (m_socket != null)
			{
			m_socket.close();
			}
		if (m_serverSocket != null)
			{
			m_serverSocket.close();
			}
		
		m_isServerStarted = false;
		m_isReceptionCreated = false;
		m_onMessageListener.onNotification("The server has been stopped !");
		}
	}
